<!DOCTYPE html>
<html lang="en-US">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>VSCode 源码解读：IPC通信机制 | 被删的前端游乐场</title>
    <meta name="generator" content="VuePress 1.8.2">
    
    <meta name="description" content="Just playing around">
    
    <link rel="preload" href="/front-end-playground/assets/css/0.styles.6ad2a9ca.css" as="style"><link rel="preload" href="/front-end-playground/assets/js/app.1e2670bf.js" as="script"><link rel="preload" href="/front-end-playground/assets/js/2.38d016d1.js" as="script"><link rel="preload" href="/front-end-playground/assets/js/3.e3f029cb.js" as="script"><link rel="preload" href="/front-end-playground/assets/js/39.4f00e013.js" as="script">
    <link rel="stylesheet" href="/front-end-playground/assets/css/0.styles.6ad2a9ca.css">
  </head>
  <body>
    <div id="app" data-server-rendered="true"><div class="theme-container"><header class="navbar"><div class="sidebar-button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" role="img" viewBox="0 0 448 512" class="icon"><path fill="currentColor" d="M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"></path></svg></div> <a href="/front-end-playground/" class="home-link router-link-active"><!----> <span class="site-name">被删的前端游乐场</span></a> <div class="links"><div class="search-box"><input aria-label="Search" autocomplete="off" spellcheck="false" value=""> <!----></div> <nav class="nav-links can-hide"><div class="nav-item"><a href="/front-end-playground/" class="nav-link">概述</a></div><div class="nav-item"><a href="/front-end-playground/front-end-basic/" class="nav-link router-link-active">前端领域</a></div><div class="nav-item"><a href="/front-end-playground/vue/" class="nav-link">Vue学习</a></div><div class="nav-item"><a href="/front-end-playground/wxapp/" class="nav-link">小程序学习</a></div><div class="nav-item"><a href="/front-end-playground/front-end-others/" class="nav-link">百家齐放</a></div><div class="nav-item"><a href="/front-end-playground/front-end-addon/" class="nav-link">前端的进击</a></div><div class="nav-item"><a href="/front-end-playground/front-end-work/" class="nav-link">前端与工作</a></div><div class="nav-item"><a href="/front-end-playground/faq.html" class="nav-link">FAQ</a></div> <a href="https://github.com/godbasin/front-end-playground" target="_blank" rel="noopener noreferrer" class="repo-link">
    Github
    <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></nav></div></header> <div class="sidebar-mask"></div> <aside class="sidebar"><nav class="nav-links"><div class="nav-item"><a href="/front-end-playground/" class="nav-link">概述</a></div><div class="nav-item"><a href="/front-end-playground/front-end-basic/" class="nav-link router-link-active">前端领域</a></div><div class="nav-item"><a href="/front-end-playground/vue/" class="nav-link">Vue学习</a></div><div class="nav-item"><a href="/front-end-playground/wxapp/" class="nav-link">小程序学习</a></div><div class="nav-item"><a href="/front-end-playground/front-end-others/" class="nav-link">百家齐放</a></div><div class="nav-item"><a href="/front-end-playground/front-end-addon/" class="nav-link">前端的进击</a></div><div class="nav-item"><a href="/front-end-playground/front-end-work/" class="nav-link">前端与工作</a></div><div class="nav-item"><a href="/front-end-playground/faq.html" class="nav-link">FAQ</a></div> <a href="https://github.com/godbasin/front-end-playground" target="_blank" rel="noopener noreferrer" class="repo-link">
    Github
    <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></nav>  <ul class="sidebar-links"><li><section class="sidebar-group collapsable depth-0" style="padding-top:10px;"><div class="kitty-main" data-v-2b653b36><span class="stand" data-v-2b653b36></span> <div class="cat" data-v-2b653b36><div class="body" data-v-2b653b36></div> <div class="head" data-v-2b653b36><div class="ear" data-v-2b653b36></div> <div class="ear" data-v-2b653b36></div></div> <div class="face" data-v-2b653b36><div class="nose" data-v-2b653b36></div> <div class="whisker-container" data-v-2b653b36><div class="whisker" data-v-2b653b36></div> <div class="whisker" data-v-2b653b36></div></div> <div class="whisker-container" data-v-2b653b36><div class="whisker" data-v-2b653b36></div> <div class="whisker" data-v-2b653b36></div></div></div> <div class="tail-container" data-v-2b653b36><div class="tail" data-v-2b653b36><div class="tail" data-v-2b653b36><div class="tail" data-v-2b653b36><div class="tail" data-v-2b653b36><div class="tail" data-v-2b653b36><div class="tail" data-v-2b653b36><div class="tail" data-v-2b653b36></div></div></div></div></div></div></div></div></div></div> <p class="sidebar-heading open"><span>前端架构</span> <span class="arrow down"></span></p> <ul class="sidebar-links sidebar-group-items"><li><a href="/front-end-playground/front-end-basic/deep-learning/module-seperate.html" class="sidebar-link">谈谈依赖和解耦</a></li><li><a href="/front-end-playground/front-end-basic/deep-learning/trace-stash.html" class="sidebar-link">大型前端项目要怎么跟踪和分析函数调用链</a></li><li><a href="/front-end-playground/front-end-basic/deep-learning/build-application.html" class="sidebar-link">前端构建大型应用</a></li><li><a href="/front-end-playground/front-end-basic/deep-learning/reactive-programing.html" class="sidebar-link">响应式编程在前端领域的应用</a></li><li><a href="/front-end-playground/front-end-basic/deep-learning/vscode-event.html" class="sidebar-link">VSCode 源码解读：事件系统设计</a></li><li><a href="/front-end-playground/front-end-basic/deep-learning/vscode-ipc.html" aria-current="page" class="active sidebar-link">VSCode 源码解读：IPC通信机制</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/front-end-playground/front-end-basic/deep-learning/vscode-ipc.html#vscode-多进程架构" class="sidebar-link">VSCode 多进程架构</a></li><li class="sidebar-sub-header"><a href="/front-end-playground/front-end-basic/deep-learning/vscode-ipc.html#ipc-通信" class="sidebar-link">IPC 通信</a></li></ul></li><li><a href="/front-end-playground/front-end-basic/deep-learning/online-doc-network.html" class="sidebar-link">在线文档的网络层设计思考</a></li><li><a href="/front-end-playground/front-end-basic/deep-learning/front-end-performance-analyze.html" class="sidebar-link">补齐Web前端性能分析的工具盲点</a></li><li><a href="/front-end-playground/front-end-basic/deep-learning/monitor-and-report.html" class="sidebar-link">前端监控体系搭建</a></li><li><a href="/front-end-playground/front-end-basic/deep-learning/why-spreadsheet-app-excited.html" class="sidebar-link">在线Excel项目到底有多刺激</a></li><li><a href="/front-end-playground/front-end-basic/deep-learning/task-runner-design.html" class="sidebar-link">如何设计一个任务管理器</a></li><li><a href="/front-end-playground/front-end-basic/deep-learning/network-design-responsibility-driven-design.html" class="sidebar-link">在线文档的网络层开发思考--职责驱动设计</a></li><li><a href="/front-end-playground/front-end-basic/deep-learning/network-design-dependency-decoupling.html" class="sidebar-link">在线文档的网络层开发思考--依赖关系梳理</a></li></ul></section></li><li><section class="sidebar-group collapsable depth-0" style="padding-top:;"><!----> <p class="sidebar-heading"><span>前端深入理解</span> <span class="arrow right"></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0" style="padding-top:;"><!----> <p class="sidebar-heading"><span>前端入门</span> <span class="arrow right"></span></p> <!----></section></li></ul> </aside> <main class="page"> <div class="theme-default-content content__default"><p>最近在研究前端大型项目中要怎么管理模块间通信，本文记录研究 VSCode 中通信机制的过程，主要包括 IPC 部分吧。</p> <h1 id="electron-的-通信机制"><a href="#electron-的-通信机制" class="header-anchor">#</a> Electron 的 通信机制</h1> <p>我们知道 Electron 是基于 Chromium + Node.js 的架构。同样基于 Chromium + Node.js 的，还有 NW.js，我们先来看看它们之间有什么不一样吧。</p> <h1 id="electron-与-nw-js"><a href="#electron-与-nw-js" class="header-anchor">#</a> Electron 与 NW.js</h1> <p>说到 Node.js 的桌面应用，基本上大家都会知道 Electron 和 NW.js。例如 VsCode 就是基于 Electron 写的，而小程序开发工具则是基于 NW.js 来开发的。</p> <p>我们知道，Node.js 和 Chromium 的运行环境不一样，它们的 JavaScript 上下文都有一些特有的全局对象和函数。在 Node.js 中包括 module、process、require等，在 Chromium 中会有 window、 documnet等。</p> <p>那么，Electron 和 NW.js 都分别是怎样管理 Node.js 和 Chromium 的呢？</p> <h3 id="nw-js-内部架构"><a href="#nw-js-内部架构" class="header-anchor">#</a> NW.js 内部架构</h3> <p>NW.js 是最早的 Node.js 桌面应用框架，架构如图1。</p> <p><img src="https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/electron_ipc_1.jpg" alt="图1"></p> <p>在 NW.js 中，将 Node.js 和 Chromium 整合在一起使用，其中做了几件事情，我们来分别看下。</p> <ol><li><p>Node.js 和 Chromium 都使用 V8 来处理执行的 JavaScript，因此在 NW.js 中它们使用相同的 V8 实例。</p></li> <li><p>Node.js 和 Chromium 都使用事件循环编程模式，但它们用不同的软件库（Node.js 使用 libuv，Chromium 使用 MessageLoop/Message-Pump）。NW.js 通过使 Chromium 使用构建在 libuv 之上的定制版本的 MessagePump 来集成 Node.js 和 Chromium 的事件循环（如图2）。</p></li></ol> <p><img src="https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/electron_ipc_3.jpg" alt="图2"></p> <ol start="3"><li>整合 Node.js 的上下文到 Chromium 中，使 Node.js 可用（如图3）。</li></ol> <p><img src="https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/electron_ipc_2.jpg" alt="图3"></p> <p>因此，虽然 NW.js 整合了 Node.js 和 Chromium，但它更接近一个前端的应用开发方式（如图4），它的入口是 index.html。</p> <p><img src="https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/electron_ipc_0.jpg" alt="图4"></p> <h3 id="electron-内部架构"><a href="#electron-内部架构" class="header-anchor">#</a> Electron 内部架构</h3> <p>Electron 强调 Chromium 源代码和应用程序进行分离，因此并没有将 Node.js 和 Chromium 整合在一起。</p> <p>在 Electron 中，分为主进程(main process)和渲染器进程(renderer processes)：</p> <ul><li>主进程：一个 Electron 应用中，有且只有一个主进程（package.json 的 main 脚本）</li> <li>渲染进程：Electron 里的每个页面都有它自己的进程，叫作渲染进程。由于 Electron 使用了 Chromium 来展示 web 页面，所以 Chromium 的多进程架构也被使用到</li></ul> <p>那么，不在一个进程当然涉及跨进程通信。于是，在 Electron 中，可以通过以下方式来进行主进程和渲染器进程的通信：</p> <ol><li>利用<code>ipcMain</code>和<code>ipcRenderer</code>模块进行 IPC 方式通信，它们是处理应用程序后端（<code>ipcMain</code>）和前端应用窗口（<code>ipcRenderer</code>）之间的进程间通信的事件触发。</li> <li>利用<code>remote</code>模块进行 RPC 方式通信。</li></ol> <blockquote><p><code>remote</code>模块返回的每个对象（包括函数），表示主进程中的一个对象（称为远程对象或远程函数）。当调用远程对象的方法时，调用远程函数、或者使用远程构造函数 (函数) 创建新对象时，实际上是在发送同步进程消息。</p></blockquote> <p>如图5，Electron 中从应用程序的后端部分到前端部分的任何状态共享（反之亦然），均通过<code>ipcMain</code>和<code>ipcRenderer</code>模块进行。这样，主进程和渲染器进程的 JavaScript 上下文将保持独立，但是可以在进程之间以显式方式传输数据。</p> <p><img src="https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/electron_ipc_4.jpg" alt="图5"></p> <h1 id="vscode-的通信机制"><a href="#vscode-的通信机制" class="header-anchor">#</a> VSCode 的通信机制</h1> <p>VSCode 基于 Electron 进行开发的，那么我们来看看 VSCode 里的相关设计吧。</p> <h2 id="vscode-多进程架构"><a href="#vscode-多进程架构" class="header-anchor">#</a> VSCode 多进程架构</h2> <p>VSCode 采用多进程架构，VSCode 启动后主要有下面的几个进程：</p> <ul><li>主进程</li> <li>渲染进程，多个，包括 Activitybar、Sidebar、Panel、Editor 等等</li> <li>插件宿主进程</li> <li>Debug 进程</li> <li>Search 进程</li></ul> <p>这些进程间的关系如图6：</p> <p><img src="https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/electron_ipc_5.png" alt="图6"></p> <p>而在 VSCode 中，这些进程的通信方式同样包括 IPC 和 RPC 两种，如图7：</p> <p><img src="https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/electron_ipc_6.jpg" alt="图7"></p> <h2 id="ipc-通信"><a href="#ipc-通信" class="header-anchor">#</a> IPC 通信</h2> <p>我们能看到，主进程和渲染进程的通信基础还是 Electron 的<code>webContents.send</code>、<code>ipcRender.send</code>、<code>ipcMain.on</code>。</p> <p>我们来看看 VSCode 中具体的 IPC 通信机制设计，包括：协议、频道、连接等。</p> <h3 id="协议"><a href="#协议" class="header-anchor">#</a> 协议</h3> <p>IPC 通信中，协议是最基础的。就像我们人和人之间的交流，需要使用约定的方式（语言、手语），在 IPC 中协议可看做是约定。</p> <p>作为通信能力，最基本的协议范围包括发送和接受消息：</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">export</span> <span class="token keyword">interface</span> <span class="token class-name">IMessagePassingProtocol</span> <span class="token punctuation">{</span>
	<span class="token function">send</span><span class="token punctuation">(</span>buffer<span class="token operator">:</span> VSBuffer<span class="token punctuation">)</span><span class="token operator">:</span> <span class="token keyword">void</span><span class="token punctuation">;</span>
	onMessage<span class="token operator">:</span> Event<span class="token operator">&lt;</span>VSBuffer<span class="token operator">&gt;</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><p>至于具体协议内容，可能包括连接、断开、事件等等：</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">Protocol</span> <span class="token keyword">implements</span> <span class="token class-name">IMessagePassingProtocol</span> <span class="token punctuation">{</span>
	<span class="token function">constructor</span><span class="token punctuation">(</span><span class="token parameter"><span class="token keyword">private</span> sender<span class="token operator">:</span> Sender<span class="token punctuation">,</span> readonly onMessage<span class="token operator">:</span> Event<span class="token operator">&lt;</span>VSBuffer<span class="token operator">&gt;</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token punctuation">}</span>
	<span class="token comment">// 发送消息</span>
	<span class="token function">send</span><span class="token punctuation">(</span>message<span class="token operator">:</span> VSBuffer<span class="token punctuation">)</span><span class="token operator">:</span> <span class="token keyword">void</span> <span class="token punctuation">{</span>
		<span class="token keyword">try</span> <span class="token punctuation">{</span>
			<span class="token keyword">this</span><span class="token punctuation">.</span>sender<span class="token punctuation">.</span><span class="token function">send</span><span class="token punctuation">(</span><span class="token string">'vscode:message'</span><span class="token punctuation">,</span> message<span class="token punctuation">.</span>buffer<span class="token punctuation">)</span><span class="token punctuation">;</span>
		<span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span>e<span class="token punctuation">)</span> <span class="token punctuation">{</span>
			<span class="token comment">// systems are going down</span>
		<span class="token punctuation">}</span>
	<span class="token punctuation">}</span>
	<span class="token comment">// 断开连接</span>
	<span class="token function">dispose</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">:</span> <span class="token keyword">void</span> <span class="token punctuation">{</span>
		<span class="token keyword">this</span><span class="token punctuation">.</span>sender<span class="token punctuation">.</span><span class="token function">send</span><span class="token punctuation">(</span><span class="token string">'vscode:disconnect'</span><span class="token punctuation">,</span> <span class="token keyword">null</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></div><p>我们能看到，IPC 的通信也使用了 VSCode 中的<code>Event</code>/<code>Emitter</code>事件机制，关于事件的更多可以参考<a href="https://godbasin.github.io/front-end-playground/front-end-basic/deep-learning/vscode-event.html" target="_blank" rel="noopener noreferrer">《VSCode源码解读：事件系统设计》<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a>。</p> <p>IPC 实际上就是发送和接收信息的能力，而要能准确地进行通信，客户端和服务端需要在同一个频道上。</p> <h3 id="频道"><a href="#频道" class="header-anchor">#</a> 频道</h3> <p>作为一个频道而言，它会有两个功能，一个是点播<code>call</code>，一个是收听，即<code>listen</code>。</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">/**
 * IChannel是对命令集合的抽象
 * call 总是返回一个至多带有单个返回值的 Promise
 */</span>
<span class="token keyword">export</span> <span class="token keyword">interface</span> <span class="token class-name">IChannel</span> <span class="token punctuation">{</span>
	call<span class="token operator">&lt;</span><span class="token constant">T</span><span class="token operator">&gt;</span><span class="token punctuation">(</span>command<span class="token operator">:</span> string<span class="token punctuation">,</span> arg<span class="token operator">?</span><span class="token operator">:</span> any<span class="token punctuation">,</span> cancellationToken<span class="token operator">?</span><span class="token operator">:</span> CancellationToken<span class="token punctuation">)</span><span class="token operator">:</span> Promise<span class="token operator">&lt;</span><span class="token constant">T</span><span class="token operator">&gt;</span><span class="token punctuation">;</span>
	listen<span class="token operator">&lt;</span><span class="token constant">T</span><span class="token operator">&gt;</span><span class="token punctuation">(</span>event<span class="token operator">:</span> string<span class="token punctuation">,</span> arg<span class="token operator">?</span><span class="token operator">:</span> any<span class="token punctuation">)</span><span class="token operator">:</span> Event<span class="token operator">&lt;</span><span class="token constant">T</span><span class="token operator">&gt;</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><h3 id="客户端与服务端"><a href="#客户端与服务端" class="header-anchor">#</a> 客户端与服务端</h3> <p>一般来说，客户端和服务端的区分主要是：发起连接的一端为客户端，被连接的一端为服务端。在 VSCode 中，主进程是服务端，提供各种频道和服务供订阅；渲染进程是客户端，收听服务端提供的各种频道/服务，也可以给服务端发送一些消息（接入、订阅/收听、离开等）。</p> <p>不管是客户端和服务端，它们都会需要发送和接收消息的能力，才能进行正常的通信。</p> <p>在 VSCode 中，客户端包括<code>ChannelClient</code>和<code>IPCClient</code>，<code>ChannelClient</code>只处理最基础的频道相关的功能，包括：</p> <ol><li>获得频道<code>getChannel</code>。</li> <li>发送频道请求<code>sendRequest</code>。</li> <li>接收请求结果，并处理<code>onResponse/onBuffer</code>。</li></ol> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">// 客户端</span>
<span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">ChannelClient</span> <span class="token keyword">implements</span> <span class="token class-name">IChannelClient</span><span class="token punctuation">,</span> IDisposable <span class="token punctuation">{</span>
	getChannel<span class="token operator">&lt;</span><span class="token constant">T</span> <span class="token keyword">extends</span> <span class="token class-name">IChannel</span><span class="token operator">&gt;</span><span class="token punctuation">(</span>channelName<span class="token operator">:</span> string<span class="token punctuation">)</span><span class="token operator">:</span> <span class="token constant">T</span> <span class="token punctuation">{</span>
		<span class="token keyword">const</span> that <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">;</span>
		<span class="token keyword">return</span> <span class="token punctuation">{</span>
			<span class="token function">call</span><span class="token punctuation">(</span><span class="token parameter">command<span class="token operator">:</span> string<span class="token punctuation">,</span> arg<span class="token operator">?</span><span class="token operator">:</span> any<span class="token punctuation">,</span> cancellationToken<span class="token operator">?</span><span class="token operator">:</span> CancellationToken</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
				<span class="token keyword">return</span> that<span class="token punctuation">.</span><span class="token function">requestPromise</span><span class="token punctuation">(</span>channelName<span class="token punctuation">,</span> command<span class="token punctuation">,</span> arg<span class="token punctuation">,</span> cancellationToken<span class="token punctuation">)</span><span class="token punctuation">;</span>
			<span class="token punctuation">}</span><span class="token punctuation">,</span>
			<span class="token function">listen</span><span class="token punctuation">(</span><span class="token parameter">event<span class="token operator">:</span> string<span class="token punctuation">,</span> arg<span class="token operator">:</span> any</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
				<span class="token keyword">return</span> that<span class="token punctuation">.</span><span class="token function">requestEvent</span><span class="token punctuation">(</span>channelName<span class="token punctuation">,</span> event<span class="token punctuation">,</span> arg<span class="token punctuation">)</span><span class="token punctuation">;</span>
			<span class="token punctuation">}</span>
		<span class="token punctuation">}</span> <span class="token keyword">as</span> <span class="token constant">T</span><span class="token punctuation">;</span>
	<span class="token punctuation">}</span>
	<span class="token keyword">private</span> <span class="token function">requestPromise</span><span class="token punctuation">(</span>channelName<span class="token operator">:</span> string<span class="token punctuation">,</span> name<span class="token operator">:</span> string<span class="token punctuation">,</span> arg<span class="token operator">?</span><span class="token operator">:</span> any<span class="token punctuation">,</span> cancellationToken <span class="token operator">=</span> CancellationToken<span class="token punctuation">.</span>None<span class="token punctuation">)</span><span class="token operator">:</span> Promise<span class="token operator">&lt;</span>any<span class="token operator">&gt;</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
	<span class="token keyword">private</span> <span class="token function">requestEvent</span><span class="token punctuation">(</span>channelName<span class="token operator">:</span> string<span class="token punctuation">,</span> name<span class="token operator">:</span> string<span class="token punctuation">,</span> arg<span class="token operator">?</span><span class="token operator">:</span> any<span class="token punctuation">)</span><span class="token operator">:</span> Event<span class="token operator">&lt;</span>any<span class="token operator">&gt;</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
	<span class="token keyword">private</span> <span class="token function">sendRequest</span><span class="token punctuation">(</span>request<span class="token operator">:</span> IRawRequest<span class="token punctuation">)</span><span class="token operator">:</span> <span class="token keyword">void</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
	<span class="token keyword">private</span> <span class="token function">send</span><span class="token punctuation">(</span>header<span class="token operator">:</span> any<span class="token punctuation">,</span> body<span class="token operator">:</span> any <span class="token operator">=</span> <span class="token keyword">undefined</span><span class="token punctuation">)</span><span class="token operator">:</span> <span class="token keyword">void</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
	<span class="token keyword">private</span> <span class="token function">sendBuffer</span><span class="token punctuation">(</span>message<span class="token operator">:</span> VSBuffer<span class="token punctuation">)</span><span class="token operator">:</span> <span class="token keyword">void</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
	<span class="token keyword">private</span> <span class="token function">onBuffer</span><span class="token punctuation">(</span>message<span class="token operator">:</span> VSBuffer<span class="token punctuation">)</span><span class="token operator">:</span> <span class="token keyword">void</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
	<span class="token keyword">private</span> <span class="token function">onResponse</span><span class="token punctuation">(</span>response<span class="token operator">:</span> IRawResponse<span class="token punctuation">)</span><span class="token operator">:</span> <span class="token keyword">void</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
	<span class="token keyword">private</span> <span class="token function">whenInitialized</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">:</span> Promise<span class="token operator">&lt;</span><span class="token keyword">void</span><span class="token operator">&gt;</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
	<span class="token function">dispose</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">:</span> <span class="token keyword">void</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></div><p>同样的，服务端包括<code>ChannelServer</code>和<code>IPCServer</code>，<code>ChannelServer</code>也只处理与频道直接相关的功能，包括：</p> <ol><li>注册频道<code>registerChannel</code>。</li> <li>监听客户端消息<code>onRawMessage/onPromise/onEventListen</code>。</li> <li>处理客户端消息并返回请求结果<code>sendResponse</code>。</li></ol> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">// 服务端</span>
<span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">ChannelServer</span><span class="token operator">&lt;</span>TContext <span class="token operator">=</span> string<span class="token operator">&gt;</span> <span class="token keyword">implements</span> <span class="token class-name">IChannelServer</span><span class="token operator">&lt;</span>TContext<span class="token operator">&gt;</span><span class="token punctuation">,</span> IDisposable <span class="token punctuation">{</span>
	<span class="token function">registerChannel</span><span class="token punctuation">(</span>channelName<span class="token operator">:</span> string<span class="token punctuation">,</span> channel<span class="token operator">:</span> IServerChannel<span class="token operator">&lt;</span>TContext<span class="token operator">&gt;</span><span class="token punctuation">)</span><span class="token operator">:</span> <span class="token keyword">void</span> <span class="token punctuation">{</span>
		<span class="token keyword">this</span><span class="token punctuation">.</span>channels<span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span>channelName<span class="token punctuation">,</span> channel<span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token punctuation">}</span>
	<span class="token keyword">private</span> <span class="token function">sendResponse</span><span class="token punctuation">(</span>response<span class="token operator">:</span> IRawResponse<span class="token punctuation">)</span><span class="token operator">:</span> <span class="token keyword">void</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
	<span class="token keyword">private</span> <span class="token function">send</span><span class="token punctuation">(</span>header<span class="token operator">:</span> any<span class="token punctuation">,</span> body<span class="token operator">:</span> any <span class="token operator">=</span> <span class="token keyword">undefined</span><span class="token punctuation">)</span><span class="token operator">:</span> <span class="token keyword">void</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
	<span class="token keyword">private</span> <span class="token function">sendBuffer</span><span class="token punctuation">(</span>message<span class="token operator">:</span> VSBuffer<span class="token punctuation">)</span><span class="token operator">:</span> <span class="token keyword">void</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
	<span class="token keyword">private</span> <span class="token function">onRawMessage</span><span class="token punctuation">(</span>message<span class="token operator">:</span> VSBuffer<span class="token punctuation">)</span><span class="token operator">:</span> <span class="token keyword">void</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
	<span class="token keyword">private</span> <span class="token function">onPromise</span><span class="token punctuation">(</span>request<span class="token operator">:</span> IRawPromiseRequest<span class="token punctuation">)</span><span class="token operator">:</span> <span class="token keyword">void</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
	<span class="token keyword">private</span> <span class="token function">onEventListen</span><span class="token punctuation">(</span>request<span class="token operator">:</span> IRawEventListenRequest<span class="token punctuation">)</span><span class="token operator">:</span> <span class="token keyword">void</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
	<span class="token keyword">private</span> <span class="token function">disposeActiveRequest</span><span class="token punctuation">(</span>request<span class="token operator">:</span> IRawRequest<span class="token punctuation">)</span><span class="token operator">:</span> <span class="token keyword">void</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
	<span class="token keyword">private</span> <span class="token function">collectPendingRequest</span><span class="token punctuation">(</span>request<span class="token operator">:</span> IRawPromiseRequest <span class="token operator">|</span> IRawEventListenRequest<span class="token punctuation">)</span><span class="token operator">:</span> <span class="token keyword">void</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
	<span class="token keyword">public</span> <span class="token function">dispose</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">:</span> <span class="token keyword">void</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></div><p>我们能看到，作为频道的直接连接对象，<code>ChannelClient</code>和<code>ChannelServer</code>的发送和接收基本上是一一对应的，像<code>sendRequest</code>和<code>sendResponse</code>等等。但<code>ChannelClient</code>只能发送请求，而<code>ChannelServer</code>只能响应请求，在阅读完整篇文章后，可以思考一下：如果我们想要实现双向通信的话，可以怎么做呢？</p> <p>我们还发现，对消息的发送和接受，<code>ChannelClient</code>和<code>ChannelServer</code>会进行序列化(<code>serialize</code>)和反序列化(<code>deserialize</code>)：</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">// 此处篇幅关系，以 deserialize 举例：</span>
<span class="token keyword">function</span> <span class="token function">deserialize</span><span class="token punctuation">(</span><span class="token parameter">reader<span class="token operator">:</span> IReader</span><span class="token punctuation">)</span><span class="token operator">:</span> any <span class="token punctuation">{</span>
	<span class="token keyword">const</span> type <span class="token operator">=</span> reader<span class="token punctuation">.</span><span class="token function">read</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">readUInt8</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token keyword">switch</span> <span class="token punctuation">(</span>type<span class="token punctuation">)</span> <span class="token punctuation">{</span>
		<span class="token keyword">case</span> DataType<span class="token punctuation">.</span>Undefined<span class="token operator">:</span> <span class="token keyword">return</span> <span class="token keyword">undefined</span><span class="token punctuation">;</span>
		<span class="token keyword">case</span> DataType<span class="token punctuation">.</span>String<span class="token operator">:</span> <span class="token keyword">return</span> reader<span class="token punctuation">.</span><span class="token function">read</span><span class="token punctuation">(</span><span class="token function">readSizeBuffer</span><span class="token punctuation">(</span>reader<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
		<span class="token keyword">case</span> DataType<span class="token punctuation">.</span>Buffer<span class="token operator">:</span> <span class="token keyword">return</span> reader<span class="token punctuation">.</span><span class="token function">read</span><span class="token punctuation">(</span><span class="token function">readSizeBuffer</span><span class="token punctuation">(</span>reader<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span>buffer<span class="token punctuation">;</span>
		<span class="token keyword">case</span> DataType<span class="token punctuation">.</span>VSBuffer<span class="token operator">:</span> <span class="token keyword">return</span> reader<span class="token punctuation">.</span><span class="token function">read</span><span class="token punctuation">(</span><span class="token function">readSizeBuffer</span><span class="token punctuation">(</span>reader<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
		<span class="token keyword">case</span> DataType<span class="token punctuation">.</span>Array<span class="token operator">:</span> <span class="token punctuation">{</span>
			<span class="token keyword">const</span> length <span class="token operator">=</span> <span class="token function">readSizeBuffer</span><span class="token punctuation">(</span>reader<span class="token punctuation">)</span><span class="token punctuation">;</span>
			<span class="token keyword">const</span> result<span class="token operator">:</span> any<span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span>

			<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> length<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
				result<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token function">deserialize</span><span class="token punctuation">(</span>reader<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
			<span class="token punctuation">}</span>

			<span class="token keyword">return</span> result<span class="token punctuation">;</span>
		<span class="token punctuation">}</span>
		<span class="token keyword">case</span> DataType<span class="token punctuation">.</span>Object<span class="token operator">:</span> <span class="token keyword">return</span> <span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">parse</span><span class="token punctuation">(</span>reader<span class="token punctuation">.</span><span class="token function">read</span><span class="token punctuation">(</span><span class="token function">readSizeBuffer</span><span class="token punctuation">(</span>reader<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></div><p>那么，<code>IPCClient</code>和<code>IPCServer</code>又起到什么作用呢？</p> <h3 id="连接"><a href="#连接" class="header-anchor">#</a> 连接</h3> <p>现在有了频道直接相关的客户端部分<code>ChannelClient</code>和服务端部分<code>ChannelServer</code>，但是它们之间需要连接起来才能进行通信。一个连接(<code>Connection</code>)由<code>ChannelClient</code>和<code>ChannelServer</code>组成。</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">interface</span> <span class="token class-name">Connection</span><span class="token operator">&lt;</span>TContext<span class="token operator">&gt;</span> <span class="token keyword">extends</span> <span class="token class-name">Client</span><span class="token operator">&lt;</span>TContext<span class="token operator">&gt;</span> <span class="token punctuation">{</span>
	readonly channelServer<span class="token operator">:</span> ChannelServer<span class="token operator">&lt;</span>TContext<span class="token operator">&gt;</span><span class="token punctuation">;</span> <span class="token comment">// 服务端</span>
	readonly channelClient<span class="token operator">:</span> ChannelClient<span class="token punctuation">;</span> <span class="token comment">// 客户端</span>
<span class="token punctuation">}</span>
</code></pre></div><p>而连接的建立，则由<code>IPCServer</code>和<code>IPCClient</code>负责。其中：</p> <ul><li><code>IPCClient</code>基于<code>ChannelClient</code>，负责简单的客户端到服务端一对一连接</li> <li><code>IPCServer</code>基于<code>channelServer</code>，负责服务端到客户端的连接，由于一个服务端可提供多个服务，因此会有多个连接</li></ul> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">// 客户端</span>
<span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">IPCClient</span><span class="token operator">&lt;</span>TContext <span class="token operator">=</span> string<span class="token operator">&gt;</span> <span class="token keyword">implements</span> <span class="token class-name">IChannelClient</span><span class="token punctuation">,</span> IChannelServer<span class="token operator">&lt;</span>TContext<span class="token operator">&gt;</span><span class="token punctuation">,</span> IDisposable <span class="token punctuation">{</span>
	<span class="token keyword">private</span> channelClient<span class="token operator">:</span> ChannelClient<span class="token punctuation">;</span>
	<span class="token keyword">private</span> channelServer<span class="token operator">:</span> ChannelServer<span class="token operator">&lt;</span>TContext<span class="token operator">&gt;</span><span class="token punctuation">;</span>
	getChannel<span class="token operator">&lt;</span><span class="token constant">T</span> <span class="token keyword">extends</span> <span class="token class-name">IChannel</span><span class="token operator">&gt;</span><span class="token punctuation">(</span>channelName<span class="token operator">:</span> string<span class="token punctuation">)</span><span class="token operator">:</span> <span class="token constant">T</span> <span class="token punctuation">{</span>
		<span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span>channelClient<span class="token punctuation">.</span><span class="token function">getChannel</span><span class="token punctuation">(</span>channelName<span class="token punctuation">)</span> <span class="token keyword">as</span> <span class="token constant">T</span><span class="token punctuation">;</span>
	<span class="token punctuation">}</span>
	<span class="token function">registerChannel</span><span class="token punctuation">(</span>channelName<span class="token operator">:</span> string<span class="token punctuation">,</span> channel<span class="token operator">:</span> IServerChannel<span class="token operator">&lt;</span>TContext<span class="token operator">&gt;</span><span class="token punctuation">)</span><span class="token operator">:</span> <span class="token keyword">void</span> <span class="token punctuation">{</span>
		<span class="token keyword">this</span><span class="token punctuation">.</span>channelServer<span class="token punctuation">.</span><span class="token function">registerChannel</span><span class="token punctuation">(</span>channelName<span class="token punctuation">,</span> channel<span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token punctuation">}</span>
<span class="token punctuation">}</span>

<span class="token comment">// 由于服务端有多个服务，因此可能存在多个连接</span>
<span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">IPCServer</span><span class="token operator">&lt;</span>TContext <span class="token operator">=</span> string<span class="token operator">&gt;</span> <span class="token keyword">implements</span> <span class="token class-name">IChannelServer</span><span class="token operator">&lt;</span>TContext<span class="token operator">&gt;</span><span class="token punctuation">,</span> IRoutingChannelClient<span class="token operator">&lt;</span>TContext<span class="token operator">&gt;</span><span class="token punctuation">,</span> IConnectionHub<span class="token operator">&lt;</span>TContext<span class="token operator">&gt;</span><span class="token punctuation">,</span> IDisposable <span class="token punctuation">{</span>
	<span class="token keyword">private</span> channels <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Map</span><span class="token operator">&lt;</span>string<span class="token punctuation">,</span> IServerChannel<span class="token operator">&lt;</span>TContext<span class="token operator">&gt;&gt;</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token keyword">private</span> _connections <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Set</span><span class="token operator">&lt;</span>Connection<span class="token operator">&lt;</span>TContext<span class="token operator">&gt;&gt;</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token comment">// 获取连接信息</span>
	<span class="token keyword">get</span> <span class="token function">connections</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">:</span> Connection<span class="token operator">&lt;</span>TContext<span class="token operator">&gt;</span><span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
	<span class="token comment">/**
	 * 从远程客户端获取频道。
	 * 通过路由器后，可以指定它要呼叫和监听/从哪个客户端。
	 * 否则，当在没有路由器的情况下进行呼叫时，将选择一个随机客户端，而在没有路由器的情况下进行侦听时，将监听每个客户端。
	 */</span>
	getChannel<span class="token operator">&lt;</span><span class="token constant">T</span> <span class="token keyword">extends</span> <span class="token class-name">IChannel</span><span class="token operator">&gt;</span><span class="token punctuation">(</span>channelName<span class="token operator">:</span> string<span class="token punctuation">,</span> router<span class="token operator">:</span> IClientRouter<span class="token operator">&lt;</span>TContext<span class="token operator">&gt;</span><span class="token punctuation">)</span><span class="token operator">:</span> <span class="token constant">T</span><span class="token punctuation">;</span>
	getChannel<span class="token operator">&lt;</span><span class="token constant">T</span> <span class="token keyword">extends</span> <span class="token class-name">IChannel</span><span class="token operator">&gt;</span><span class="token punctuation">(</span>channelName<span class="token operator">:</span> string<span class="token punctuation">,</span> <span class="token function-variable function">clientFilter</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token parameter">client<span class="token operator">:</span> Client<span class="token operator">&lt;</span>TContext<span class="token operator">&gt;</span></span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> boolean<span class="token punctuation">)</span><span class="token operator">:</span> <span class="token constant">T</span><span class="token punctuation">;</span>
	getChannel<span class="token operator">&lt;</span><span class="token constant">T</span> <span class="token keyword">extends</span> <span class="token class-name">IChannel</span><span class="token operator">&gt;</span><span class="token punctuation">(</span>channelName<span class="token operator">:</span> string<span class="token punctuation">,</span> routerOrClientFilter<span class="token operator">:</span> IClientRouter<span class="token operator">&lt;</span>TContext<span class="token operator">&gt;</span> <span class="token operator">|</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">client<span class="token operator">:</span> Client<span class="token operator">&lt;</span>TContext<span class="token operator">&gt;</span></span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> boolean<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token operator">:</span> <span class="token constant">T</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
	<span class="token comment">// 注册频道</span>
	<span class="token function">registerChannel</span><span class="token punctuation">(</span>channelName<span class="token operator">:</span> string<span class="token punctuation">,</span> channel<span class="token operator">:</span> IServerChannel<span class="token operator">&lt;</span>TContext<span class="token operator">&gt;</span><span class="token punctuation">)</span><span class="token operator">:</span> <span class="token keyword">void</span> <span class="token punctuation">{</span>
		<span class="token keyword">this</span><span class="token punctuation">.</span>channels<span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span>channelName<span class="token punctuation">,</span> channel<span class="token punctuation">)</span><span class="token punctuation">;</span>
		<span class="token comment">// 添加到连接中</span>
		<span class="token keyword">this</span><span class="token punctuation">.</span>_connections<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token parameter">connection</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
			connection<span class="token punctuation">.</span>channelServer<span class="token punctuation">.</span><span class="token function">registerChannel</span><span class="token punctuation">(</span>channelName<span class="token punctuation">,</span> channel<span class="token punctuation">)</span><span class="token punctuation">;</span>
		<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></div><p>前面也说过，客户端可理解为渲染进程，服务端可理解为主进程。</p> <p>而连接的详细建立过程，可以参考<a href="https://juejin.im/post/6844904050052300814" target="_blank" rel="noopener noreferrer">《vscode-通信机制设计解读(Electron)》<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a>一文。这里借用里面的一张图：</p> <p><img src="https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/electron_ipc_7.jpg" alt="图8"></p> <h1 id="参考"><a href="#参考" class="header-anchor">#</a> 参考</h1> <ul><li><a href="https://zhaomenghuan.js.org/blog/vscode-workbench-source-code-interpretation.html" target="_blank" rel="noopener noreferrer">vscode 定制开发 —— Workbench 源码解读及实战前言<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li> <li><a href="https://zhaomenghuan.js.org/blog/vscode-custom-development-basic-preparation.html" target="_blank" rel="noopener noreferrer">vscode 定制开发 —— 基础准备<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li> <li><a href="https://livebook.manning.com/book/cross-platform-desktop-applications/chapter-6/59" target="_blank" rel="noopener noreferrer">【译】探索NW.js和Electron的内部<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li> <li><a href="https://juejin.im/post/6844904050052300814" target="_blank" rel="noopener noreferrer">vscode-通信机制设计解读(Electron)<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li> <li><a href="https://imweb.io/topic/5b3b72ab4d378e703a4f4435" target="_blank" rel="noopener noreferrer">你不知道的 Electron (一)：神奇的 remote 模块<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li></ul> <h1 id="结束语"><a href="#结束语" class="header-anchor">#</a> 结束语</h1> <p>IPC 和 RPC 通信是由于 Electron 的跨进程通信出现的。那么，我们还可以思考下，在一般的前端开发场景下，除了跨进程以外是否还有其他场景可以参考呢？</p> <p>至于 RPC 的部分，由于目前也没有强业务相关，有空我们下次再约。</p></div> <!----> <footer class="page-edit"><div class="edit-link"><a href="https://github.com/godbasin/front-end-playground/edit/sourcecode/docs/front-end-basic/deep-learning/vscode-ipc.md" target="_blank" rel="noopener noreferrer">帮阿猪改善此页面！</a> <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></div> <!----> <blockquote>部分文章中使用了一些网站的截图，如果涉及侵权，请告诉我删一下谢谢~</blockquote> <div style="margin-top:30px;"><div class="el-row" style="margin-left:-10px;margin-right:-10px;"><div class="el-col el-col-24 el-col-sm-0 el-col-md-2 el-col-lg-4" style="padding-left:10px;padding-right:10px;display:block;"><div style="width:1px;height:1px;"></div></div> <div class="el-col el-col-24 el-col-sm-24 el-col-md-18 el-col-lg-16" style="padding-left:10px;padding-right:10px;"><div class="el-card box-card is-always-shadow"><div class="el-card__header"><div class="clearfix"><span>温馨提示喵</span></div></div><div class="el-card__body"> <div class="el-row" style="margin-left:-10px;margin-right:-10px;"><div class="el-col el-col-24 el-col-xs-24 el-col-sm-12" style="padding-left:10px;padding-right:10px;"><div class="el-image"><div class="image-slot"><img src="https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/assets/img/loading.gif" style="width:100%;"></div><!----></div></div> <div class="el-col el-col-24 el-col-xs-24 el-col-sm-12" style="padding-left:10px;padding-right:10px;"><div class="copyright-text"><div>本文版权归作者所有，欢迎转载，但未经作者同意必须保留此段声明，且在文章页面明显位置给出原文连接，否则保留追究法律责任的权利。</div> <div>出处：被删的前端游乐场</div> <div>作者：<a href="https://github.com/godbasin" target="_blank">被删</a></div></div></div></div></div></div></div></div></div></footer> <div class="page-nav"><p class="inner"><span class="prev">
        ←
        <a href="/front-end-playground/front-end-basic/deep-learning/vscode-event.html" class="prev">
          VSCode 源码解读：事件系统设计
        </a></span> <span class="next"><a href="/front-end-playground/front-end-basic/deep-learning/online-doc-network.html">
          在线文档的网络层设计思考
        </a>
        →
      </span></p></div>  <div class="gitalk-container theme-default-content"><div id="gitalk-container" class="content"></div></div></main> <div id="kitty-container"><span><div role="tooltip" id="el-popover-6291" aria-hidden="true" class="el-popover el-popper" style="width:undefinedpx;display:none;"><!----><img src="https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/2code2.jpg" class="image"> <div class="text">牡羊猪的猫粮罐</div> </div><span class="el-popover__reference-wrapper"><div id="kitty" style="background:url(https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/assets/img/kitty0.svg);"></div></span></span> <div class="el-dialog__wrapper" style="display:none;"><div role="dialog" aria-modal="true" aria-label="牡羊猪是这样渐渐胖成猪的喵（点击图片可以切换噢）" class="el-dialog" style="margin-top:15vh;"><div class="el-dialog__header"><span class="el-dialog__title">牡羊猪是这样渐渐胖成猪的喵（点击图片可以切换噢）</span><button type="button" aria-label="Close" class="el-dialog__headerbtn"><i class="el-dialog__close el-icon el-icon-close"></i></button></div><!----><!----></div></div></div></div><div class="global-ui"></div></div>
    <script src="/front-end-playground/assets/js/app.1e2670bf.js" defer></script><script src="/front-end-playground/assets/js/2.38d016d1.js" defer></script><script src="/front-end-playground/assets/js/3.e3f029cb.js" defer></script><script src="/front-end-playground/assets/js/39.4f00e013.js" defer></script>
  </body>
</html>
